"""
国际服光叔临时脚本，稳定性低
"""

from time import *
from PyGameAutoAndroid import *

#   battle_sequence - 预设战斗序列 - 此设计为临时方案
#                     由于每位玩家拥有的角色，技能，星级均不同，技能位置，队伍组成也不同，因此这段必须自己设计并提供数值
#                     此参数为object array：
#                           第1层为战斗回合层，数组有多少对象元素就有多少战斗回合
#                           第2层为战斗对象层，对象有两个字段
#                               all_boost  - 是否需要按下全体boost按钮
#                               skill_list - 只有4个元素，分别代表从上到下第1234位角色
#
#                           skill_list内为角色技能层，有4个元素，第一个元素为使用哪个技能，第二个元素为使用几级Boost，第三个元素为指向队友型技能指定的目标，第四个元素为指定敌人
#                           关于技能，可选值为-1, 0, 1, 2, 3, 10, 11, 12, 13
#                               -1 - 跳过本角色
#                               0  - 使用普攻
#                               1  - 使用第一个技能
#                               2  - 使用第二个技能
#                               3  - 使用第三个技能
#                               10 - 交换角色，使用普攻
#                               11 - 交换角色，使用第一个技能
#                               12 - 交换角色，使用第二个技能
#                               13 - 交换角色，使用第三个技能
#                           关于Boost，可选值为1, 2, 3, 4
#                               1  - 无Boost
#                               2  - 2级Boost
#                               3  - 3级Boost
#                               4  - 满级Boost

battle_sequence = [
    # 第1回合
    {
        'skill_list': [
            [1, 4, 0, 0],
            [1, 1, 0, 0],
            [3, 1, 0, 0],
            [1, 4, 0, 'varkyn'],
        ],
        'all_boost': False,
    },
    # 第2回合
    {
        'skill_list': [
            [11, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [2, 1, 0, 'tactical-researcher'],
        ],
        'all_boost': False,
    },
    # 第3回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [2, 1, 0, 'tactical-researcher'],
            [12, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第4回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [12, 4, 0, 0],
            [13, 4, 0, 0],
            [12, 1, 0, 'varkyn'],
        ],
        'all_boost': False,
    },
    # 第5回合
    {
        'skill_list': [
            [11, 4, 0, 0],
            [11, 1, 0, 0],
            [13, 1, 0, 0],
            [2, 4, 0, 0],
        ],
        'all_boost': False,
    },
    # 第6回合
    {
        'skill_list': [
            [11, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
            [1, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第7回合
    {
        'skill_list': [
            [13, 1, 0, 0],
            [13, 1, 0, 'varkyn'],
            [13, 3, 0, 0],
            [12, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第8回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [3, 3, 0, 0],
            [1, 1, 0, 0],
            [13, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第9回合
    {
        'skill_list': [
            [13, 1, 0, 0],
            [-1, 1, 0, 0],
            [2, 1, 0, 'varkyn'],
            [13, 1, 0, 0],
        ],
        'all_boost': True,
    },
    # 第10回合
    {
        'skill_list': [
            [-1, 1, 0, 0],
            [5, 1, 0, 0],
            [-1, 1, 0, 0],
            [-1, 1, 0, 0],
        ],
        'all_boost': False,
    },
    # 第n回合 - 如有需求可以一直加下去，但要保证你的战斗流程每次都相同，不可以这次战斗4回合，下次战斗5回合
]

region = 'en'

round_per_recover = 1

#   -------------------------------------------------------------------------------------------------
#                               ※如果不懂编程或看不懂代码，从这里往下可以不用看了※
#   -------------------------------------------------------------------------------------------------
#   开发者参数部分 - 通过调整参数改变脚本性能
stability_mode = 0
turn_on_in_game_log = False
turn_on_console_log = True

#   常数部分 - 游戏内固定参数，比如地图按钮的位置。
#   当更换设备时，由于屏幕分辨率发生变化，这些数值都会失效，放在这里统一更改，比去代码里寻找效率更高。
#   单点坐标常数
screen_center_coord = [640, 360]  # 屏幕正中
skills_panel_coord = [[1150, 90],
                      [1150, 230],
                      [1150, 370],
                      [1150, 520]]
switch_character_coord = {
    'tw': [793, 626],
    'en': [1105, 635],
}
skills_coord = {
    'tw': [[[850, 170, 0, 0],
            [850, 170, 1025, 170],
            [850, 170, 1115, 170],
            [850, 170, 1200, 170]],
           [[850, 290, 0, 0],
            [850, 290, 1025, 290],
            [850, 290, 1115, 290],
            [850, 290, 1200, 290]],
           [[850, 400, 0, 0],
            [850, 400, 1025, 400],
            [850, 400, 1115, 400],
            [850, 400, 1200, 400]],
           [[850, 520, 0, 0],
            [850, 520, 1025, 520],
            [850, 520, 1115, 520],
            [850, 520, 1200, 520]]],
    'en': [[[850, 200, 0, 0],
            [850, 200, 1025, 170],
            [850, 200, 1115, 170],
            [850, 200, 1200, 170]],
           [[850, 305, 0, 0],
            [850, 305, 1025, 290],
            [850, 305, 1115, 290],
            [850, 305, 1200, 290]],
           [[850, 410, 0, 0],
            [850, 410, 1025, 400],
            [850, 410, 1115, 400],
            [850, 410, 1200, 400]],
           [[850, 525, 0, 0],
            [850, 525, 1025, 520],
            [850, 525, 1115, 520],
            [850, 525, 1200, 520]]],
}
start_battle_btn_coord = [1083, 643]
all_boost_btn_coord = [864, 643]

#   多点找色常数
character_standby = ["#F0EBE8", "1|0|#F0EBE8", [681, 168, 683, 169]]
battle_idling = {
    'tw': ["#FFFFFF", "1|1|#FFFFFF", [1082, 642, 1084, 644]],
    'en': ["#FFFFFF", "1|1|#FFFFFF", [1038, 629, 1040, 631]],
}
black_screen_exist = ["#000000", "1|1|#000000", [639, 359, 641, 361]]
character_all_boosted = ["#DEDEDE", "1|0|#F0F0F0", [905, 638, 907, 639]]

skills_panel_exist = [["#FFFFFF", "0|1|#FFFFFF", [999, 125, 1000, 127]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 268, 1000, 270]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 411, 1000, 413]],
                      ["#FFFFFF", "0|1|#FFFFFF", [999, 554, 1000, 556]]]
skills_panel_standby = {
    'tw': ["#F0EBE8", "-48|9|#6F6F6F", [633, 168, 682, 178]],
    'en': ["#6F6F6F", "52|-8|#F0EBE8", [633, 191, 686, 200]],
}
switch_character_done = {
    'tw': ["#272727", "19|0|#373635, 8|-9|#262626, 0|11|#262626, 19|11|#262626", [728, 615, 748, 636]],     # 取消交替按钮存在，代表交替完成
    'en': ["#F0EBE8", "1|1|#F0EBE8", [783, 20, 785, 22]],       # 检查技能面板上方Front和Back
}
enemy_exist = {
    'varkyn': {
        'statement': ["#F0EBE8", "1|1|#F0EBE8, 1|2|#F0EBE8, 1|3|#F0EBE8, 2|4|#F0EBE8, 2|5|#F0EBE8, 3|6|#F0EBE8", [24, 415, 262, 457]],
        'delta': [45, -35],
    },
    'tactical-researcher': {
        'statement': ["#F0EBE8", "0|-1|#F0EBE8, 0|-2|#F0EBE8, 1|0|#F0EBE8, 2|0|#F0EBE8, 0|1|#F0EBE8, 0|2|#F0EBE8", [187, 508, 454, 553]],
        'delta': [15, -50],
    },
}
skill_boost_level_applied = {
    'tw': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 137, 1244, 138]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 280, 1244, 281]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 423, 1244, 424]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1242, 566, 1244, 567]],
        },
    ],
    'en': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 148, 1266, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 142, 1267, 143]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 138, 1243, 140]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 291, 1266, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 285, 1267, 286]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 281, 1243, 283]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 434, 1266, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 428, 1267, 429]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 424, 1243, 426]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1264, 577, 1266, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1265, 571, 1267, 572]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1242, 567, 1243, 569]],
        },
    ],
}
attack_boost_level_applied = {
    'tw': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 148, 1264, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 142, 1261, 143]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 145, 1259, 146]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 291, 1264, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 285, 1261, 286]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 288, 1259, 289]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 434, 1264, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 428, 1261, 429]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 431, 1259, 432]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1262, 577, 1264, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 571, 1261, 572]],
            '4': ["#FFFFFF", "1|0|#FFFFFF", [1257, 574, 1259, 575]],
        },
    ],
    'en': [
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 148, 1263, 149]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 142, 1261, 143]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 144, 1262, 146]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 291, 1263, 292]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 285, 1261, 286]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 287, 1262, 289]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 434, 1263, 435]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 428, 1261, 429]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 430, 1262, 432]],
        },
        {
            '2': ["#FFFFFF", "1|0|#FFFFFF", [1261, 577, 1263, 578]],
            '3': ["#FFFFFF", "1|0|#FFFFFF", [1259, 571, 1261, 572]],
            '4': ["#FFFFFF", "0|1|#FFFFFF", [1261, 573, 1262, 575]],
        },
    ],
}


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   底层方法部分 - 底层操作，对小派API再封装以实现某些特殊效果。
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def log(text):
    if turn_on_in_game_log:
        xp.log(text)
    if turn_on_console_log:
        xp.console(text)


def wait(t):
    _t = t + 0.2 * stability_mode
    # log("等待：" + str(_t) + "秒")
    sleep(_t)


def tap(x, y):
    _t = 0.05 + 0.02 * stability_mode
    # log("点击：" + str(x) + ", " + str(y))
    xp.tap(x, y, _t)
    sleep(_t + 0.01)


def tap_preset_coord(coord):
    tap(coord[0], coord[1])


def check_statement(statement):
    return xp.findColor(statement[0], statement[1], statement[2][0], statement[2][1], statement[2][2], statement[2][3])


def tap_preset_coord_with_checking(coord, statement, check_per_turn=5, interval=0.10, inverted=False):
    while True:
        tap_preset_coord(coord)
        for i in range(check_per_turn):
            wait(interval)
            if not inverted and check_statement(statement):
                return True
            if inverted and not check_statement(statement):
                return True


def tap_found_coord_with_checking(statement, interval=0.10, dx=0, dy=0):
    while True:
        found_coord = check_statement(statement)
        if found_coord:
            tap(found_coord.x + dx, found_coord.y + dy)
            return
        wait(interval)


def wait_with_checking(statement, max_turns=-1, interval=0.10, inverted=False):
    t = 0
    while True:
        wait(interval)
        t += 1
        if not inverted and check_statement(statement):
            return True
        if inverted and not check_statement(statement):
            return True
        if t == max_turns:
            return False


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   单元模块部分
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def tap_skills_panel(n):
    # 检查技能面板是否开启需要注意，开局时漂浮移动的buff层级最高，会挡住技能面板，导致按键失效或判断错误
    return tap_preset_coord_with_checking(skills_panel_coord[n], battle_idling[region], inverted=True)


def tap_switch_character():
    return tap_preset_coord_with_checking(switch_character_coord[region], switch_character_done[region], interval=0.15)


def tap_skill(boost, x1, y1, x2=0, y2=0):
    # xp.tap(x1, y1, 0.25)
    # sleep(0.18)
    delay = 0.08 if boost == 1 else 0.15 + 0.02 * (boost - 1)
    xp.tap(x1, y1, delay)
    sleep(delay - 0.08)
    if x2 != 0 and y2 != 0:
        tap(x2, y2)


def tap_start_battle():
    return tap_preset_coord_with_checking(start_battle_btn_coord, battle_idling[region], check_per_turn=1, inverted=True)


def tap_until_black_screen(coord):
    return tap_preset_coord_with_checking(coord, black_screen_exist, check_per_turn=1)


def tap_all_boost():
    return tap_preset_coord_with_checking(all_boost_btn_coord, character_all_boosted, check_per_turn=5, interval=0.1)


def tap_enemy(enemy):
    return tap_found_coord_with_checking(enemy_exist[enemy]['statement'], dx=enemy_exist[enemy]['delta'][0], dy=enemy_exist[enemy]['delta'][1])


def wait_skills_panel_shown():
    return wait_with_checking(skills_panel_standby[region], max_turns=10)


def wait_skills_panel_gone():
    return wait_with_checking(skills_panel_standby[region], max_turns=20, interval=0.05, inverted=True)


def wait_battle_idling(interval=0.5):
    return wait_with_checking(battle_idling[region], interval=interval)


def wait_black_screen_start():
    return wait_with_checking(black_screen_exist, interval=0.5)


def wait_black_screen_end():
    return wait_with_checking(black_screen_exist, interval=0.5, inverted=True)


#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
#   复合模块部分
#   -------------------------------------------------------------------------------------------------
#   -------------------------------------------------------------------------------------------------
def open_skills_panel(n):
    count = 0
    while True:
        if count > 0:
            log("【注意】：技能面板没有打开，重试")
        tap_skills_panel(n)
        count += 1
        if wait_skills_panel_shown():
            return


def await_black_screen_transition():
    wait_black_screen_start()
    wait_black_screen_end()


#   -------------------------------------------------------------------------------------------------
# def use_skill(n, boost=1):
#     skill_coord = skills_coord[n][boost-1]
#     while True:
#         tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
#         if wait_skills_panel_gone():
#             return
#   -------------------------------------------------------------------------------------------------
def use_skill(n, boost=1, t=0):
    if n == 5:
        wait(0.1)
        tap(705, 93)
        wait(0.5)
        tap(923, 399)
        if wait_battle_idling():
            return
    skill_coord = skills_coord[region][n][boost - 1]
    count = 0
    while True:
        if count > 0:
            log("【注意】：重复点击技能")
        tap_skill(boost, skill_coord[0], skill_coord[1], skill_coord[2], skill_coord[3])
        if t != 0:
            wait(0.3)
            tap(skills_panel_coord[t-1][0], skills_panel_coord[t-1][1])
            wait(0.3)
        count += 1
        if wait_skills_panel_gone():
            return


def run_preset_character_action(n, action, retry=False):
    switch_character = action[0] > 9
    skill_to_use = action[0] % 10 if action[0] != -1 else -1
    boost_level = action[1]
    target_character = action[2]
    target_enemy = action[3]
    require_checking = False if boost_level == 1 else True

    if skill_to_use == -1:
        return
    open_skills_panel(n)

    if target_enemy != 0 and not retry:
        wait(0.3)
        tap_enemy(target_enemy)
        wait(0.3)

    if switch_character and not retry:
        tap_switch_character()
        # 国际服 - 切换完角色之后不做检查的话，会在瞬间完成以下动作：
        # 1.点击技能（但是面板未就绪，技能没有点上）
        # 2.检查技能面板解除（由于技能面板尚未显示，因此检查会通过）
        # 3.点击下一位角色的技能面板（由于上一位角色面板未消失，因此通过）
        # 4.点击下一位角色的技能（但是点成了上一位的）
        # 原因：因为台服检查的是底部的取消交替按钮，这个按钮的UI是最后出现的，因此检查到了必定切换完成且就绪，但是国际服检查的是顶部Front/Back，检查到的时候不一定就绪。
        if region == "en":
            wait_skills_panel_shown()
    use_skill(skill_to_use, boost_level, target_character)

    if not require_checking:
        return
    boost_level_applied = attack_boost_level_applied[region] if skill_to_use == 0 else skill_boost_level_applied[region]
    boost_level_check_result = wait_with_checking(boost_level_applied[n][str(boost_level)], max_turns=10)
    if not boost_level_check_result:
        log("【注意】：角色boost等级错误，重新使用技能")
        run_preset_character_action(n, action, retry=True)


def run_preset_turn_sequence(turn):
    all_boost = turn['all_boost']
    skill_list = turn['skill_list']

    wait_battle_idling()
    for n, character_action in enumerate(skill_list):
        character_action[1] = 1 if all_boost else character_action[1]
        run_preset_character_action(n, character_action)
    wait_battle_idling(0.1)
    tap_all_boost() if all_boost else None
    tap_start_battle()


def run_preset_battle_sequence(sequence_list):
    for i, sequence in enumerate(sequence_list):
        # log("开始第" + str(i+1) + "回合")
        run_preset_turn_sequence(sequence)
    tap_until_black_screen(start_battle_btn_coord)


memories_read_btn_coord = [1102, 190]
memories_ok_btn_coord = [700, 530]
memories_confirm_read = ["#FFFFFF", "1|0|#FFFFFF", [782, 590, 784, 591]]
memories_read_exist = ["#FFFFFF", "1|0|#FFFFFF", [1082, 181, 1084, 182]]


def tap_memories_read():
    return tap_preset_coord_with_checking(memories_read_btn_coord, memories_confirm_read, check_per_turn=1)


def tap_memories_ok_after_battle():
    return tap_preset_coord_with_checking(memories_ok_btn_coord, memories_read_exist, check_per_turn=1)


def run_varkyn_script():
    total_count = 0
    while True:
        total_count += 1
        xp.log("第" + str(total_count) + "轮")
        start_time = time()

        # 战斗前
        tap_memories_read()
        tap_until_black_screen([798, 600])
        await_black_screen_transition()
        xp.tap(640, 360, 2.5)
        wait(2.5)
        await_black_screen_transition()

        # 战斗 - 1
        run_preset_battle_sequence(battle_sequence)
        await_black_screen_transition()
        xp.tap(640, 360, 2.5)
        wait(2.5)
        await_black_screen_transition()

        # 战斗后
        tap_memories_ok_after_battle()

        xp.log("本轮用时：" + str(int(time() - start_time)) + "秒")
        log("------------------------")


run_varkyn_script()
